package br.uniceub.fsw.arquitetura.persistencia.conexao;

import java.sql.Connection;
import java.sql.SQLException;

import br.uniceub.fsw.arquitetura.persistencia.exception.BancoDadosException;

/**
 * Objeto que representa a conexão que está sendo utilizada no momento
 * por uma determinada chamada (thread, requisição). Essa conexão é
 * obtida de um pool.
 * 
 * @author Daniel Rochetti
 *
 */
public class ConexaoAtual {

	/**
	 * Configura se a conexão atual participa de uma transação. Caso
	 * sim ela só será fechada e devolvida ao pool após o término
	 * da transação.
	 */
	private static ThreadLocal<Boolean> participaTransacao =
			new ThreadLocal<Boolean>();

	/**
	 * Representa a conexão atual.
	 */
	private static ThreadLocal<Connection> conexaoAtual =
		new ThreadLocal<Connection>();

	/**
	 * Obtém a conexão atual ou abre (pega do pool) caso não exista nenhuma
	 * ativa atualmente, para essa chamada.
	 * @return Connection conexao.
	 */
	public static Connection getConexao() {
		
		Connection conn = conexaoAtual.get();
		if (conn == null) {
			conn = getPoolConexoes().getConexao();
			conexaoAtual.set(conn);
		}
		
		// Se a conexão não foi iniciada em uma transação, então ela será readOnly
		// e o autoCommit será true, caso contrário o autoCommit será desabilitado
		// e a conexão poderá persistir dados (no momento do commit da transação)
		try {
			boolean participandoTransacao = participaTransacao.get() != null
					&& participaTransacao.get().booleanValue();
			conn.setReadOnly(!participandoTransacao);
			conn.setAutoCommit(!participandoTransacao);
		} catch (SQLException e) {
			throw new BancoDadosException(e.getMessage(), e);
		}		
		return conn;
	}

	/**
	 * Obtém a referência ao pool de conexões.
	 * @return PoolConexões.
	 */
	protected static PoolConexoes getPoolConexoes() {
		
		return PoolConexoes.getInstancia();
	}

	/**
	 * Configura se essa conexão participa de um transação. Caso participe
	 * ela só será liberada após o término da transação.
	 * @param participa
	 */
	public static void setParticipaTransacao(Boolean participa) {
		participaTransacao.set(participa);
	}

	/**
	 * Libera a conexão atual. Caso ela esteja participando de uma transação
	 * a chamada do DAO não surtirá efeito, ela só será liberada após o
	 * término da transação.
	 */
	public static void liberarConexao() {
		
		boolean participa = participaTransacao.get() != null ?
				participaTransacao.get().booleanValue() : false;
		if (!participa) {
			Connection conexao = conexaoAtual.get();
			getPoolConexoes().liberarConexao(conexao);
			conexaoAtual.set(null);
			participaTransacao.set(null);
		}
	}
}
